package nl.weeaboo.sh.editor.area;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.TexturePaint;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

import nl.weeaboo.sh.editor.HitBoxEditor2;
import nl.weeaboo.sh.level.Level;
import nl.weeaboo.sh.model.TileModel;
import nl.weeaboo.sh.model.TileSetIndex;
import timon.common.GraphicsUtil;
import timon.common.Log;

@SuppressWarnings("serial")
public class TileSetPanel extends JPanel {

	private float scale = 2.0f;
	private List<SelectionListener> listeners;
	
	private BufferedImage checkerboardImage;
	private Map<String, EditorTileSet> tileSets;
	private EditorTileSet selected;
	private TileSetIndex selectedTile;
	
	public TileSetPanel() {
		listeners = new LinkedList<SelectionListener>();
		tileSets = new HashMap<String, EditorTileSet>();
		
		try {
			checkerboardImage = ImageIO.read(HitBoxEditor2.class.getResource("checkerboard.png"));
		} catch (IOException e) {
			Log.showError(e);
		}
		
		addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent e) {
				if (selected == null) return;
				
				int ts = (int)(Level.tileSize * scale);
				int x = Math.max(0, Math.min(selected.getWidth()-1, e.getX() / ts));
				int y = Math.max(0, Math.min(selected.getHeight()-1, e.getY() / ts));
				
				TileModel tm = selected.getModel().getTileModel(x, y);				
				setSelectedTile(tm.getIndex());
			}
		});
		addMouseMotionListener(new MouseMotionListener() {
			public void mouseDragged(MouseEvent e) {
				if (selected == null) return;
				
				int ts = (int)(Level.tileSize * scale);
				int x = Math.max(0, Math.min(selected.getWidth()-1, e.getX() / ts));
				int y = Math.max(0, Math.min(selected.getHeight()-1, e.getY() / ts));

				TileModel tm = selected.getModel().getTileModel(x, y);				
				setSelectedTile(tm.getIndex());
			}
			public void mouseMoved(MouseEvent e) {
			}
		});
	}
	
	public void dispose() {
		tileSets.clear();
	}
	
	public void addListener(SelectionListener l) {
		listeners.add(l);
	}
	public void removeListener(SelectionListener l) {
		listeners.remove(l);
	}
	
	public void paintComponent(Graphics graphics) {
		super.paintComponent(graphics);
		
		if (selected == null) return;			
		Graphics2D g = (Graphics2D)graphics;
		
		g.setBackground(Color.BLACK);
		g.clearRect(0, 0, getWidth(), getHeight());
		
		int ts = (int)(Level.tileSize * scale);
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, selected.getWidth()*ts, selected.getHeight()*ts);

		if (checkerboardImage == null) {
			g.setBackground(Color.BLACK);
			g.clearRect(0, 0, selected.getWidth()*ts, selected.getHeight()*ts);
		} else {
			g.setPaint(new TexturePaint(checkerboardImage, new Rectangle2D.Float(0, 0,
					checkerboardImage.getWidth(), checkerboardImage.getHeight())));
			g.fillRect(0, 0, selected.getWidth()*ts, selected.getHeight()*ts);
			g.setColor(Color.BLACK);
		}
		
		for (int y = 0; y < selected.getHeight(); y++) {
			for (int x = 0; x < selected.getWidth(); x++) {
				TileModel tm = selected.getModel().getTileModel(x, y);
				selected.drawTileImage(g, tm.getIndex(), x*ts, y*ts, ts, ts, this);
			}
		}
		
		if (selectedTile != null) {
			Color c = new Color(255, 0, 0);
			g.setColor(GraphicsUtil.setAlpha(c, 150));
			g.fillRect(selectedTile.getX()*ts, selectedTile.getY()*ts, ts, ts);
			g.setColor(c);
			g.drawRect(selectedTile.getX()*ts, selectedTile.getY()*ts, ts-1, ts-1);
		}
	}	
	
	public TileSetIndex getSelectedTile() {
		return selectedTile;
	}
	
	public void setTileSets(Map<String, EditorTileSet> ts) {
		tileSets.clear();		
		
		if (ts != null) {
			tileSets.putAll(ts);
		}
	}
	public void setSelected(EditorTileSet ts) {
		if (selected != ts) {
			selected = ts;
			
			int tileSize = (int)(Level.tileSize * scale);
			if (selected != null) {
				setPreferredSize(new Dimension(selected.getWidth()*tileSize, selected.getHeight()*tileSize));
			} else {
				setPreferredSize(new Dimension(1, 1));
			}
			invalidate();
			getParent().validate();

			selectedTile = null;
			fireSelectionChanged();
			
			repaint();
		}
	}
	public void setSelectedTile(TileSetIndex index) {
		if (selectedTile != index) {
			selectedTile = selected.getModel().getTileModel(index.getX(), index.getY()).getIndex();
			
			repaint();
			fireSelectionChanged();
		}
	}
	
	protected void fireSelectionChanged() {
		final TileSetIndex sel = selectedTile;
		for (SelectionListener l : listeners) {
			l.onSelected(sel);
		}
	}
}
